package com.hzw.saas.service.hpc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.hpc.IHpcAccountProviderService;
import com.hzw.saas.api.hpc.IHpcAccountRecordService;
import com.hzw.saas.api.hpc.IHpcAccountService;
import com.hzw.saas.api.hpc.bo.HpcAccountBo;
import com.hzw.saas.api.hpc.bo.HpcAccountProviderBo;
import com.hzw.saas.api.hpc.enums.HpcAccountPoolStatus;
import com.hzw.saas.api.hpc.enums.HpcProviderType;
import com.hzw.saas.api.property.IPropertyService;
import com.hzw.saas.api.property.enmus.SysDictKeyEnum;
import com.hzw.saas.common.config.annotation.RedisProcessLock;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.service.hpc.event.HpcAccountAddEvent;
import com.hzw.saas.service.hpc.event.HpcAccountDeleteEvent;
import com.hzw.saas.service.hpc.mapper.HpcAccountMapper;
import com.hzw.saas.service.hpc.model.HpcAccount;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 用户超算中心帐号表 服务实现类
 * </p>
 *
 * @author sonam
 * @since 2021-03-22
 */
@RequiredArgsConstructor
@Service("hpcAccountServiceImpl")
public class HpcAccountServiceImpl extends ServiceImpl<HpcAccountMapper, HpcAccount> implements IHpcAccountService, IService<HpcAccount> {
    @Resource(name = "hpcAccountRecordServiceImpl")
    private IHpcAccountRecordService hpcAccountRecordService;
    @Resource(name = "hpcAccountServiceImpl")
    private IHpcAccountService self;
    @Resource(name = IPropertyService.SYS_DICT_BEAN)
    private IPropertyService<SysDictKeyEnum> propertyService;
    @Resource
    private IHpcAccountProviderService providerService;

    private final ApplicationEventPublisher applicationEventPublisher;
    private final HpcAccountMapper hpcAccountMapper;
    private final MapperFacade mapperFacade;


    @Override
    public HpcAccountBo getAccount(HpcAccountBo hpcAccountPoolBo) {
        HpcAccount hpcAccountPool = mapperFacade.map(hpcAccountPoolBo, HpcAccount.class);
        return mapperFacade.map(this.getOne(Wrappers.<HpcAccount>query().setEntity(hpcAccountPool)), HpcAccountBo.class);
    }

    @Override
    public List<HpcAccountBo> query(HpcAccountBo hpcAccountPoolBo) {
        HpcAccount hpcAccountPool = mapperFacade.map(hpcAccountPoolBo, HpcAccount.class);
        List<HpcAccount> hpcAccountPools = this.list(Wrappers.<HpcAccount>query().setEntity(hpcAccountPool));
        return mapperFacade.mapAsList(hpcAccountPools, HpcAccountBo.class);
    }

    @Override
    public HpcAccountBo getById(String pid) {
        if (StringUtil.isBlank(pid)) return null;
        return mapperFacade.map(super.getById(pid), HpcAccountBo.class);
    }

    @Override
    public boolean update(HpcAccountBo hpcAccountBo) {
        String hpcAccountName = hpcAccountBo.getHpcAccount();
        String hpcAccountId = hpcAccountBo.getHpcAccountId();

        if (StrUtil.isBlank(hpcAccountId)) {
            return false;
        }

        HpcAccountBo hpcAccount = this.getById(hpcAccountId);
        if (Objects.isNull(hpcAccount)) {
            return false;
        }

        String providerId = hpcAccount.getProviderId();
        HpcAccountProviderBo hpcAccountProviderBo = providerService.getById(providerId);

        if(Objects.nonNull(hpcAccountProviderBo) && Objects.equals(HpcProviderType.QY.value(), hpcAccountProviderBo.getProviderCode())) {
            AssertUtil.assertThrow("更新失败，青云账号不能修改用户名或者密码", !Objects.equals(hpcAccountBo.getHpcAccount(), hpcAccount.getHpcAccount()) || !Objects.equals(hpcAccountBo.getHpcPassword(), hpcAccount.getHpcPassword()));
        }

        if (StrUtil.isNotBlank(hpcAccountName)) { // 账号不为空
            if (this.lambdaQuery()
                .eq(HpcAccount::getHpcAccount, hpcAccountName)
                .eq(HpcAccount::getHpcAccountId, hpcAccountId).count() == 0) {
                // 说明需要更新HPC用户名
                HpcAccountPoolStatus hpcAccountStatus = hpcAccountRecordService.getHpcAccountStatus(hpcAccountId);
                AssertUtil.assertThrow("操作失败，无法修改HPC帐号名称，该HPC帐号已绑定帐号", hpcAccountStatus == HpcAccountPoolStatus.BE_OCCUPIED);
            }
        }
        return this.updateById(mapperFacade.map(hpcAccountBo, HpcAccount.class));
    }

    @Override
    @Transactional
    public void addBatch(List<HpcAccountBo> hpcAccountBos) {
        this.saveBatch(mapperFacade.mapAsList(hpcAccountBos, HpcAccount.class));
        applicationEventPublisher.publishEvent(new HpcAccountAddEvent(hpcAccountBos));
    }

    @Override
    @Transactional
    @RedisProcessLock(lockName = "BoundHpcAccount", key = "#hpcAccountId")
    public void delete(String hpcAccountId) {
        HpcAccountBo account = self.getAccount(new HpcAccountBo().setHpcAccountId(hpcAccountId));
        AssertUtil.assertThrow("操作失败,当前HPC账号不存在", Objects.isNull(account));
        // 检测是否有关联了HPC账号
        HpcAccountPoolStatus hpcAccountStatus = hpcAccountRecordService.getHpcAccountStatus(account.getHpcAccountId());
        AssertUtil.assertThrow("操作失败,请先解绑该HPC账号", hpcAccountStatus == HpcAccountPoolStatus.BE_OCCUPIED);
        this.removeById(hpcAccountId);
        applicationEventPublisher.publishEvent(new HpcAccountDeleteEvent(account));
    }

    @Override
    public int getHpcAccountSumCount(HpcProviderType providerType) {
        // 简单一点直接获取供应商ID集合查询
        List<String> providerIds = providerService.getProviderIds(providerType);
        return this.lambdaQuery()
            .in(CollectionUtil.isNotEmpty(providerIds), HpcAccount::getProviderId, providerIds)
            .count();
    }

    @Override
    public int getUsableHpcAccountCount(HpcProviderType providerType) {
        // 可以的HPC帐号数量
        return this.hpcAccountMapper.getUsableAccountCount(providerType);
    }

    @Override
    public int getNeedAddHpcCoreCount(HpcProviderType providerType, Double balanceCore) {
        if (Objects.isNull(balanceCore)) {
            try {
                String propertyValue = propertyService.getPropertyValue(SysDictKeyEnum.LACKED_HPC_TIME, "1000");
                balanceCore = Double.parseDouble(propertyValue);
            } catch (Exception e) {
                balanceCore = 1000.0d;
            }
        }
        // 简单一点直接获取供应商ID集合查询
        List<String> providerIds = providerService.getProviderIds(providerType);
        return this.lambdaQuery()
            .in(CollectionUtil.isNotEmpty(providerIds), HpcAccount::getProviderId, providerIds)
            .le(HpcAccount::getCoreTimeAvailable, balanceCore).count();
    }

}
